/**
 @file ctc_asw_register.c

 @author  Copyright (C) 2020 Centec Networks Inc.  All rights reserved.

 @date 2020-06-15

 @version v2.0

 The file contains all chip APIs
*/

/****************************************************************************
*
* Header Files
*
****************************************************************************/
#include "ctc_asw_common.h"
#include "ctc_asw_register.h"
#include "ctc_asw_port.h"
#include "ctc_asw_pdu.h"

#include "asw/include/drv_api.h"
/****************************************************************************
*
* Defines and Macros
*
*****************************************************************************/
#define CTC_ASW_PDU_ACT_TCP  1
#define CTC_ASW_PDU_ACT_UDP  0
#define CTC_PDU_INVALID_INDEX  0xFF
/****************************************************************************
*
* Global and Declaration
*
*****************************************************************************/
static uint32 spmac_group_bitmap[CTC_MAX_LOCAL_CHIP_NUM][2] = {0};

/****************************************************************************
*
*  Functions
*
*****************************************************************************/
STATIC int32
_ctc_asw_l2pdu_set_action(uint8 lchip, uint32 index, uint8 is_pmac, uint8 action, uint8 is_valid)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    PmacAct_m pmac_act;
    SmacAct_m smac_act;

    if (0 == is_pmac)
    {
        sal_memset(&smac_act, 0, sizeof(SmacAct_m));
        cmd = DRV_IOR(SmacAct_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, index, cmd, &smac_act);
        SetSmacAct(V, daChange_f, &smac_act, 1);
        SetSmacAct(V, notModify_f, &smac_act, 1);
        SetSmacAct(V, bypassLoopback_f, &smac_act, 1);
        SetSmacAct(V, bypassProtect_f, &smac_act, 1);
        SetSmacAct(V, bypassLearnDrop_f, &smac_act, 1);
        SetSmacAct(V, bypassStp_f, &smac_act, 0);
        SetSmacAct(V, bypassEvcDrop_f, &smac_act, 1);
        SetSmacAct(V, bypassEapDrop_f, &smac_act, 1);

        if (CTC_PDU_L2PDU_ACTION_TYPE_REDIRECT_TO_CPU == action)
        {
            SetSmacAct(V, drop_f, &smac_act, 1);
            SetSmacAct(V, copyToCpu_f, &smac_act, 1);
        }
        else if (CTC_PDU_L2PDU_ACTION_TYPE_COPY_TO_CPU == action)
        {
            SetSmacAct(V, drop_f, &smac_act, 0);
            SetSmacAct(V, copyToCpu_f, &smac_act, 1);
        }
        else if (CTC_PDU_L2PDU_ACTION_TYPE_FWD == action)
        {
            SetSmacAct(V, drop_f, &smac_act, 0);
            SetSmacAct(V, copyToCpu_f, &smac_act, 0);
        }
        else if (CTC_PDU_L2PDU_ACTION_TYPE_DISCARD == action)
        {
            SetSmacAct(V, drop_f, &smac_act, 1);
            SetSmacAct(V, copyToCpu_f, &smac_act, 0);
        }
        else
        {
            return CTC_E_INVALID_PARAM;
        }
        SetSmacAct(V, valid_f, &smac_act, is_valid?1:0);
        cmd = DRV_IOW(SmacAct_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, index, cmd, &smac_act);
    }
    else
    {
        sal_memset(&pmac_act, 0, sizeof(PmacAct_m));

        cmd = DRV_IOR(PmacAct_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, index, cmd, &pmac_act);
        SetPmacAct(V, daChange_f, &smac_act, 1);
        SetPmacAct(V, notModify_f, &pmac_act, 1);
        SetPmacAct(V, bypassLoopback_f, &pmac_act, 1);
        SetPmacAct(V, bypassProtect_f, &pmac_act, 1);
        SetPmacAct(V, bypassLearnDrop_f, &pmac_act, 1);
        SetPmacAct(V, bypassStp_f, &pmac_act, 0);
        SetPmacAct(V, bypassEvcDrop_f, &pmac_act, 1);
        SetPmacAct(V, bypassEapDrop_f, &pmac_act, 1);

        if (CTC_PDU_L2PDU_ACTION_TYPE_REDIRECT_TO_CPU == action)
        {
            SetPmacAct(V, drop_f, &pmac_act, 1);
            SetPmacAct(V, copyToCpu_f, &pmac_act, 1);
        }
        else if (CTC_PDU_L2PDU_ACTION_TYPE_COPY_TO_CPU == action)
        {
            SetPmacAct(V, drop_f, &pmac_act, 0);
            SetPmacAct(V, copyToCpu_f, &pmac_act, 1);
        }
        else if (CTC_PDU_L2PDU_ACTION_TYPE_FWD == action)
        {
            SetPmacAct(V, drop_f, &pmac_act, 0);
            SetPmacAct(V, copyToCpu_f, &pmac_act, 0);
        }
        else if (CTC_PDU_L2PDU_ACTION_TYPE_DISCARD == action)
        {
            SetPmacAct(V, drop_f, &pmac_act, 1);
            SetPmacAct(V, copyToCpu_f, &pmac_act, 0);
        }
        else
        {
            return CTC_E_INVALID_PARAM;
        }
        SetPmacAct(V, valid_f, &pmac_act, is_valid?1:0);
        cmd = DRV_IOW(PmacAct_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, index, cmd, &pmac_act);
    }

    return ret;
}

STATIC int32
_ctc_asw_l2pdu_get_action(uint8 lchip, uint32 index, uint8 is_pmac, uint8* action, uint8* is_valid)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    PmacAct_m pmac_act;
    SmacAct_m smac_act;
    uint8 is_drop = 0;
    uint8 copy_to_cpu = 0;

    if (0 == is_pmac)
    {
        sal_memset(&smac_act, 0, sizeof(SmacAct_m));
        cmd = DRV_IOR(SmacAct_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, index, cmd, &smac_act);

        *is_valid = GetSmacAct(V, valid_f, &smac_act);
        is_drop = GetSmacAct(V, drop_f, &smac_act);
        copy_to_cpu = GetSmacAct(V, copyToCpu_f, &smac_act);

        if ((1 == is_drop) && (1 == copy_to_cpu))
        {
            *action = CTC_PDU_L2PDU_ACTION_TYPE_REDIRECT_TO_CPU;
        }
        else if ((0 == is_drop) && (1 == copy_to_cpu))
        {
            *action = CTC_PDU_L2PDU_ACTION_TYPE_COPY_TO_CPU;
        }
        else if ((0 == is_drop) && (0 == copy_to_cpu))
        {
            *action = CTC_PDU_L2PDU_ACTION_TYPE_FWD;
        }
        else if ((1 == is_drop) && (0 == copy_to_cpu))
        {
            *action = CTC_PDU_L2PDU_ACTION_TYPE_DISCARD;
        }
    }
    else
    {
        sal_memset(&pmac_act, 0, sizeof(PmacAct_m));

        cmd = DRV_IOR(PmacAct_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, index, cmd, &pmac_act);
        *is_valid = GetPmacAct(V, valid_f, &pmac_act);

        is_drop = GetPmacAct(V, drop_f, &pmac_act);
        copy_to_cpu = GetPmacAct(V, copyToCpu_f, &pmac_act);

        if ((1 == is_drop) && (1 == copy_to_cpu))
        {
            *action = CTC_PDU_L2PDU_ACTION_TYPE_REDIRECT_TO_CPU;
        }
        else if ((0 == is_drop) && (1 == copy_to_cpu))
        {
            *action = CTC_PDU_L2PDU_ACTION_TYPE_COPY_TO_CPU;
        }
        else if ((0 == is_drop) && (0 == copy_to_cpu))
        {
            *action = CTC_PDU_L2PDU_ACTION_TYPE_FWD;
        }
        else if ((1 == is_drop) && (0 == copy_to_cpu))
        {
            *action = CTC_PDU_L2PDU_ACTION_TYPE_DISCARD;
        }
    }

    return ret;
}

#define ______API______
/**
 @brief  Classify layer2 pdu based on macda, layer2 header protocol

 @param[in] l2pdu_type  CTC_PDU_L2PDU_TYPE_XXX

 @param[in] index  classify layer2 pdu index,
                               based on macda,max index num is 16,
                               based on macda low24 bit, max index num is 10,
                               based on layer2 header protocol, max index num is 16,

 @param[in] key  layer2 pdu action key

 @return SDK_E_XXX

*/
int32
ctc_asw_l2pdu_classify_l2pdu(uint8 lchip, ctc_pdu_l2pdu_type_t l2pdu_type, uint8 index,
                                   ctc_pdu_l2pdu_key_t* key)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    PmacKey_m pmac_key;
    hw_mac_addr_t   hw_mac = {0};

    CTC_PTR_VALID_CHECK(key);
    CTC_VALUE_RANGE_CHECK(index, CTC_ASW_SPMAC_KEY_NUM, CTC_ASW_SPMAC_KEY_NUM+CTC_ASW_PMAC_KEY_NUM-1);

    sal_memset(&pmac_key, 0, sizeof(PmacKey_m));
    CTC_API_LOCK(lchip);
    if (CTC_PDU_L2PDU_TYPE_MACDA == l2pdu_type)
    {
        SetPmacKey(V, maskOfSourcePort_f, &pmac_key, 1);
        SetPmacKey(V, maskOfDestinationPort_f, &pmac_key, 1);
        SetPmacKey(V, maskOfIpProtocol_f, &pmac_key, 1);
        SetPmacKey(V, maskOfSubtype_f, &pmac_key, 1);
        SetPmacKey(V, maskOfOpcode_f, &pmac_key, 1);
        SetPmacKey(V, maskL4Status_f, &pmac_key, 1);
        SetPmacKey(V, maskIpFrag_f, &pmac_key, 1);
        SetPmacKey(V, maskOfIpStatus_f, &pmac_key, 1);
        SetPmacKey(V, maskOfFramingType_f, &pmac_key, 1);
        SetPmacKey(V, maskOfEthertype_f, &pmac_key, 1);
        SetPmacKey(V, maskOfDa_f, &pmac_key, 0);
        FDB_SET_HW_MAC(hw_mac, key->l2pdu_by_mac.mac);
        SetPmacKey(A, da_f, &pmac_key, hw_mac);
    }
    else if (CTC_PDU_L2PDU_TYPE_L2HDR_PROTO == l2pdu_type)
    {
        SetPmacKey(V, maskOfSourcePort_f, &pmac_key, 1);
        SetPmacKey(V, maskOfDestinationPort_f, &pmac_key, 1);
        SetPmacKey(V, maskOfIpProtocol_f, &pmac_key, 1);
        SetPmacKey(V, maskOfSubtype_f, &pmac_key, 1);
        SetPmacKey(V, maskOfOpcode_f, &pmac_key, 1);
        SetPmacKey(V, maskL4Status_f, &pmac_key, 1);
        SetPmacKey(V, maskIpFrag_f, &pmac_key, 1);
        SetPmacKey(V, maskOfIpStatus_f, &pmac_key, 1);
        SetPmacKey(V, maskOfFramingType_f, &pmac_key, 1);
        SetPmacKey(V, maskOfEthertype_f, &pmac_key, 0);
        SetPmacKey(V, maskOfDa_f, &pmac_key, 1);
        SetPmacKey(V, eType_f, &pmac_key, key->l2hdr_proto);
    }
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

    SetPmacKey(V, valid_f, &pmac_key, 1);
    cmd = DRV_IOW(PmacKey_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, index-CTC_ASW_SPMAC_KEY_NUM, cmd, &pmac_key);
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief  Get layer2 pdu key

 @param[in] l2pdu_type  CTC_PDU_L2PDU_TYPE_XXX

 @param[in] index  classify layer2 pdu index,
                               based on macda,max index num is 16,
                               based on layer2 header protocol, max index num is 16,

 @param[out] key  layer2 pdu action key

 @return SDK_E_XXX

*/
int32
ctc_asw_l2pdu_get_classified_key(uint8 lchip, ctc_pdu_l2pdu_type_t l2pdu_type, uint8 index,
                                       ctc_pdu_l2pdu_key_t* key)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    uint32 value = 0;
    PmacKey_m pmac_key;
    hw_mac_addr_t   hw_mac = {0};

    CTC_PTR_VALID_CHECK(key);
    CTC_VALUE_RANGE_CHECK(index, CTC_ASW_SPMAC_KEY_NUM, CTC_ASW_SPMAC_KEY_NUM+CTC_ASW_PMAC_KEY_NUM-1);

    CTC_API_LOCK(lchip);
    sal_memset(&pmac_key, 0, sizeof(PmacKey_m));
    cmd = DRV_IOR(PmacKey_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, index-CTC_ASW_SPMAC_KEY_NUM, cmd, &pmac_key);
    value = GetPmacKey(V, valid_f, &pmac_key);
    if (0 == value)
    {
        ret = CTC_E_NOT_EXIST;
        goto roll_back_0;
    }
    if ((CTC_PDU_L2PDU_TYPE_MACDA == l2pdu_type) && !GetPmacKey(V, maskOfDa_f, &pmac_key))
    {
        GetPmacKey(A, da_f, &pmac_key, hw_mac);
        CTC_ASW_SET_USER_MAC(key->l2pdu_by_mac.mac,hw_mac);
    }
    else if ((CTC_PDU_L2PDU_TYPE_L2HDR_PROTO == l2pdu_type) && !GetPmacKey(V, maskOfEthertype_f, &pmac_key))
    {
        key->l2hdr_proto = GetPmacKey(V, eType_f, &pmac_key);
    }
    else
    {
        ret = CTC_E_INVALID_PARAM;
    }

roll_back_0:
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief  Set layer2 pdu global property

 @param[in] l2pdu_type  CTC_PDU_L2PDU_TYPE_XXX

 @param[in] index  classify layer2 pdu index,
                               based on macda,max index num is 4,
                               based on macda low24 bit, max index num is 10,
                               based on layer2 header protocol, max index num is 16,
                               based on layer3 type, the index  is equal to l3type (CTC_PARSER_L3_TYPE_XXX),
                               based on bpdu,index num is 1
 @param[in] action  layer2 pdu global property filed

 @return SDK_E_XXX

*/
int32
ctc_asw_l2pdu_set_global_action(uint8 lchip, ctc_pdu_l2pdu_type_t l2pdu_type, uint8 index,
                                      ctc_pdu_global_l2pdu_action_t* action)
{
    int32 ret = CTC_E_NONE;
    uint8 is_pmac = 0;
    uint8 act_val = 0;

    CTC_PTR_VALID_CHECK(action);
    CTC_MAX_VALUE_CHECK(index, CTC_ASW_SPMAC_KEY_NUM+CTC_ASW_PMAC_KEY_NUM-1);

    CTC_API_LOCK(lchip);
    if (index >= CTC_ASW_SPMAC_KEY_NUM)
    {
        is_pmac = 1;
        index -= CTC_ASW_SPMAC_KEY_NUM;
    }
    if (action->copy_to_cpu)
    {
        act_val = CTC_PDU_L2PDU_ACTION_TYPE_REDIRECT_TO_CPU;
    }
    else
    {
        act_val = CTC_PDU_L2PDU_ACTION_TYPE_FWD;
    }
    ret = _ctc_asw_l2pdu_set_action(lchip, index*CTC_ASW_MAX_SPMAC_GROUP, is_pmac, act_val, action->entry_valid);
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief  Get layer2 pdu global property

 @param[in] l2pdu_type  CTC_PDU_L2PDU_TYPE_XXX

 @param[in] index  classify layer2 pdu index,
                               based on macda,max index num is 4,
                               based on macda low24 bit, max index num is 10,
                               based on layer2 header protocol, max index num is 16,
                               based on layer3 type, the index  is equal to l3type (CTC_PARSER_L3_TYPE_XXX),
                               based on bpdu,index num is 1
 @param[out] action  layer2 pdu global property filed

 @return SDK_E_XXX

*/
int32
ctc_asw_l2pdu_get_global_action(uint8 lchip, ctc_pdu_l2pdu_type_t l2pdu_type, uint8 index,
                                      ctc_pdu_global_l2pdu_action_t* action)
{
    int32 ret = CTC_E_NONE;
    uint8 is_pmac = 0;
    uint8 is_valid = 0;
    uint8 act_val = 0;

    CTC_PTR_VALID_CHECK(action);
    CTC_MAX_VALUE_CHECK(index, CTC_ASW_SPMAC_KEY_NUM+CTC_ASW_PMAC_KEY_NUM-1);

    CTC_API_LOCK(lchip);
    if (index >= CTC_ASW_SPMAC_KEY_NUM)
    {
        is_pmac = 1;
        index -= CTC_ASW_SPMAC_KEY_NUM;
    }
    ret = _ctc_asw_l2pdu_get_action(lchip, index*CTC_ASW_MAX_SPMAC_GROUP, is_pmac, &act_val, &is_valid);

    action->copy_to_cpu = (CTC_PDU_L2PDU_ACTION_TYPE_COPY_TO_CPU == act_val)?1:0;
    action->entry_valid = is_valid;
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief  Per port control layer2 pdu action

 @param[in] gport  global port

 @param[in] action_index  per port control action index,it's from action_index from ctc_pdu_global_l2pdu_action_t

 @param[in] action  layer2 pdu action type

 @return SDK_E_XXX

*/
int32
ctc_asw_l2pdu_set_port_action(uint8 lchip, uint32 gport, uint8 action_index,
                                    ctc_pdu_port_l2pdu_action_t action)
{
    int32 ret = CTC_E_NONE;
    uint8 spmac_grp_id = 0;
    uint32 index = 0;
    uint8 is_pmac = 0;
    uint8 is_alloc = 1;

    if (CTC_PDU_INVALID_INDEX != action_index)
    {
        CTC_MAX_VALUE_CHECK(action_index, CTC_ASW_SPMAC_KEY_NUM+CTC_ASW_PMAC_KEY_NUM-1);
    }
    CTC_MAX_VALUE_CHECK(action, MAX_CTC_PDU_L2PDU_ACTION_TYPE-1);
    CTC_MAX_GPORT_CHECK(gport);
    CTC_API_LOCK(lchip);
    _ctc_asw_port_get_internal_property(lchip, gport, CTC_PORT_INT_PROP_SMAC_GRP_ID, &index);
    if ((0 == index) && (CTC_PDU_INVALID_INDEX == action_index))
    {
        ret = CTC_E_NOT_EXIST;
        goto roll_back_0;
    }
    if (0 == index)
    {
        CTC_ERROR_GOTO(_ctc_asw_bitmap_alloc(lchip,spmac_group_bitmap[lchip], 1, CTC_ASW_MAX_SPMAC_GROUP, &index), ret, roll_back_0);
        is_alloc = 1;
    }
    else if (CTC_PDU_INVALID_INDEX == action_index)
    {
        CTC_ERROR_GOTO(_ctc_asw_bitmap_free(lchip,spmac_group_bitmap[lchip], index), ret, roll_back_0);
        CTC_ERROR_GOTO(_ctc_asw_port_set_internal_property(lchip, gport, CTC_PORT_INT_PROP_SMAC_GRP_ID, 0), ret, roll_back_0);
        goto roll_back_0;
    }

    spmac_grp_id = index;
    CTC_ERROR_GOTO(_ctc_asw_port_set_internal_property(lchip, gport, CTC_PORT_INT_PROP_SMAC_GRP_ID, index), ret, roll_back_1);
    if (action_index < CTC_ASW_SPMAC_KEY_NUM)
    {
        is_pmac = 0;
        index = spmac_grp_id + CTC_ASW_MAX_SPMAC_GROUP*action_index;
    }
    else
    {
        is_pmac = 1;
        action_index -= CTC_ASW_SPMAC_KEY_NUM;
        index = spmac_grp_id + CTC_ASW_MAX_SPMAC_GROUP*action_index;
    }

    CTC_ERROR_GOTO(_ctc_asw_l2pdu_set_action(lchip, index, is_pmac, action, 1), ret, roll_back_1);
    CTC_API_UNLOCK(lchip);
    return CTC_E_NONE;
roll_back_1:
    if (is_alloc)
    {
        _ctc_asw_bitmap_free(lchip,spmac_group_bitmap[lchip], spmac_grp_id);
    }
roll_back_0:
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief  Per port control layer2 pdu action

 @param[in] gport  global port

 @param[in] action_index  per port control action index,it's from action_index from ctc_pdu_global_l2pdu_action_t

 @param[out] action  layer2 pdu action type

 @return SDK_E_XXX

*/
int32
ctc_asw_l2pdu_get_port_action(uint8 lchip, uint32 gport, uint8 action_index,
                                    ctc_pdu_port_l2pdu_action_t* action)
{
    int32 ret = CTC_E_NONE;
    uint32 index = 0;
    uint8 is_valid = 0;
    uint8 act_val = 0;
    uint8 is_pmac = 0;

    CTC_PTR_VALID_CHECK(action);
    CTC_MAX_VALUE_CHECK(action_index, CTC_ASW_SPMAC_KEY_NUM+CTC_ASW_PMAC_KEY_NUM-1);
    CTC_MAX_GPORT_CHECK(gport);

    CTC_API_LOCK(lchip);
    _ctc_asw_port_get_internal_property(lchip, gport, CTC_PORT_INT_PROP_SMAC_GRP_ID, &index);
    if (0 == index)
    {
        ret = CTC_E_NOT_EXIST;
        goto roll_back_0;
    }
    if (action_index < CTC_ASW_SPMAC_KEY_NUM)
    {
        is_pmac = 0;
        index = index + CTC_ASW_MAX_SPMAC_GROUP*action_index;
    }
    else
    {
        is_pmac = 1;
        action_index -= CTC_ASW_SPMAC_KEY_NUM;
        index = index + CTC_ASW_MAX_SPMAC_GROUP*action_index;
    }
    _ctc_asw_l2pdu_get_action(lchip, index, is_pmac, &act_val, &is_valid);
    if (is_valid)
    {
        *action = act_val;
    }
    else
    {
        ret = CTC_E_NOT_EXIST;
    }
roll_back_0:
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**@}*/ /*end of @addtogroup  l2pdu L2PDU */

/**
 @addtogroup  l3pdu L3PDU
 @{
*/

/**
 @brief  Classify layer3 pdu based on layer3 header protocol, layer4 dest port

 @param[in] l3pdu_type  CTC_PDU_L3PDU_TYPE_XXX

 @param[in] index  classify layer3 pdu index,
                               based on layer3 header protocol, max index num is 8
                               based on layer4 dest port, max index num is 8

 @param[in] key  layer3 pdu action key

 @return SDK_E_XXX

*/
int32
ctc_asw_l3pdu_classify_l3pdu(uint8 lchip, ctc_pdu_l3pdu_type_t l3pdu_type, uint8 index,
                                   ctc_pdu_l3pdu_key_t* key)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    uint32 value = 0;
    PmacKey_m pmac_key;

    CTC_PTR_VALID_CHECK(key);
    CTC_VALUE_RANGE_CHECK(index, CTC_ASW_SPMAC_KEY_NUM, CTC_ASW_SPMAC_KEY_NUM+CTC_ASW_PMAC_KEY_NUM-1);

    sal_memset(&pmac_key, 0, sizeof(PmacKey_m));

    CTC_API_LOCK(lchip);
    if (CTC_PDU_L3PDU_TYPE_L3HDR_PROTO == l3pdu_type)
    {
        SetPmacKey(V, maskOfSourcePort_f, &pmac_key, 1);
        SetPmacKey(V, maskOfDestinationPort_f, &pmac_key, 1);
        SetPmacKey(V, maskOfIpProtocol_f, &pmac_key, 0);
        SetPmacKey(V, maskOfSubtype_f, &pmac_key, 1);
        SetPmacKey(V, maskOfOpcode_f, &pmac_key, 1);
        SetPmacKey(V, maskL4Status_f, &pmac_key, 1);
        SetPmacKey(V, maskIpFrag_f, &pmac_key, 1);
        SetPmacKey(V, maskOfIpStatus_f, &pmac_key, 1);
        SetPmacKey(V, maskOfFramingType_f, &pmac_key, 1);
        SetPmacKey(V, maskOfEthertype_f, &pmac_key, 1);
        SetPmacKey(V, maskOfDa_f, &pmac_key, 1);
        SetPmacKey(V, ipProtocol_f, &pmac_key, key->l3hdr_proto);
    }
    else if (CTC_PDU_L3PDU_TYPE_LAYER4_PORT == l3pdu_type)
    {
        SetPmacKey(V, maskOfSourcePort_f, &pmac_key, 1);
        SetPmacKey(V, maskOfDestinationPort_f, &pmac_key, 0);
        SetPmacKey(V, maskOfIpProtocol_f, &pmac_key, 1);
        SetPmacKey(V, maskOfSubtype_f, &pmac_key, 1);
        SetPmacKey(V, maskOfOpcode_f, &pmac_key, 1);
        SetPmacKey(V, maskL4Status_f, &pmac_key, 1);
        SetPmacKey(V, maskIpFrag_f, &pmac_key, 1);
        SetPmacKey(V, maskOfIpStatus_f, &pmac_key, 1);
        SetPmacKey(V, maskOfFramingType_f, &pmac_key, 1);
        SetPmacKey(V, maskOfEthertype_f, &pmac_key, 1);
        SetPmacKey(V, maskOfDa_f, &pmac_key, 1);
        SetPmacKey(V, destinationPortNumber_f, &pmac_key, key->l3pdu_by_port.dest_port);
        value = 0;
        if (key->l3pdu_by_port.is_tcp)
        {
            CTC_BIT_SET(value, CTC_ASW_PDU_ACT_TCP);
        }
        if (key->l3pdu_by_port.is_udp)
        {
            CTC_BIT_SET(value, CTC_ASW_PDU_ACT_UDP);
        }
        SetPmacKey(V, l4Status_f, &pmac_key, value);
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
        goto roll_back_0;
    }
    SetPmacKey(V, valid_f, &pmac_key, 1);
    cmd = DRV_IOW(PmacKey_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, index-CTC_ASW_SPMAC_KEY_NUM, cmd, &pmac_key);
roll_back_0:
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief  Get layer3 pdu classified key

 @param[in] l3pdu_type  CTC_PDU_L3PDU_TYPE_XXX

 @param[in] index  classify layer3 pdu index,
                               based on layer3 header protocol, max index num is 8
                               based on layer4 dest port, max index num is 8

 @param[out] key  layer3 pdu action key

 @return SDK_E_XXX

*/
int32
ctc_asw_l3pdu_get_classified_key(uint8 lchip, ctc_pdu_l3pdu_type_t l3pdu_type, uint8 index,
                                       ctc_pdu_l3pdu_key_t* key)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    uint32 value = 0;
    PmacKey_m pmac_key;

    CTC_PTR_VALID_CHECK(key);
    CTC_VALUE_RANGE_CHECK(index, CTC_ASW_SPMAC_KEY_NUM, CTC_ASW_SPMAC_KEY_NUM+CTC_ASW_PMAC_KEY_NUM-1);

    sal_memset(&pmac_key, 0, sizeof(PmacKey_m));

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(PmacKey_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, index-CTC_ASW_SPMAC_KEY_NUM, cmd, &pmac_key);
    if(!GetPmacKey(V, valid_f, &pmac_key))
    {
        ret = CTC_E_NOT_EXIST;
        goto roll_back_0;
    }

    if ((CTC_PDU_L3PDU_TYPE_L3HDR_PROTO == l3pdu_type) && !GetPmacKey(V, maskOfIpProtocol_f, &pmac_key))
    {
        key->l3hdr_proto = GetPmacKey(V, ipProtocol_f, &pmac_key);

    }
    else if ((CTC_PDU_L3PDU_TYPE_LAYER4_PORT == l3pdu_type) && !GetPmacKey(V, maskOfDestinationPort_f, &pmac_key))
    {
        key->l3pdu_by_port.dest_port = GetPmacKey(V, destinationPortNumber_f, &pmac_key);
        value = GetPmacKey(V, l4Status_f, &pmac_key);
        if (CTC_IS_BIT_SET(value, CTC_ASW_PDU_ACT_UDP))
        {
            key->l3pdu_by_port.is_udp = 1;
        }
        if (CTC_IS_BIT_SET(value, CTC_ASW_PDU_ACT_TCP))
        {
            key->l3pdu_by_port.is_tcp = 1;
        }
    }
    else
    {
        ret = CTC_E_NOT_SUPPORT;
        goto roll_back_0;
    }

roll_back_0:
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief Initialize the chip module and set the local chip number of the linecard
*/
int32
ctc_asw_pdu_init(uint8 lchip, void* pdu_global_cfg)
{
    return CTC_E_NONE;
}

int32
ctc_asw_pdu_deinit(uint8 lchip)
{
    return CTC_E_NONE;
}
